{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "38e2f556",
   "metadata": {},
   "source": [
    "# Deep Research Agent - UK Global Talent Visa Eligibility Evaluator\n",
    "\n",
    "## Project Overview\n",
    "The Deep Research Agent is an intelligent system that automates the evaluation of candidate profiles against UK Global Talent Visa requirements. It combines real-time web research with AI-powered analysis to provide comprehensive, up-to-date assessments of visa eligibility, helping applicants understand their chances of success before submitting their applications."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "53c710a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports\n",
    "from agents import Agent, WebSearchTool, trace, Runner, gen_trace_id, function_tool\n",
    "from agents.model_settings import ModelSettings\n",
    "from pydantic import BaseModel, Field\n",
    "from dotenv import load_dotenv\n",
    "import asyncio\n",
    "import sendgrid\n",
    "from pypdf import PdfReader\n",
    "import os\n",
    "from sendgrid.helpers.mail import Mail, Email, To, Content\n",
    "from typing import Dict\n",
    "from IPython.display import display, Markdown\n",
    "from openai import OpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "3972374b",
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv(override=True)\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "464325ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Schema and Classes\n",
    "class WebSearchItem(BaseModel):\n",
    "    reason: str = Field(\n",
    "        description=\"Your reasoning for why this search is important to the query.\"\n",
    "    )\n",
    "\n",
    "    query: str = Field(description=\"The search term to use for the web search.\")\n",
    "\n",
    "\n",
    "class WebSearchPlan(BaseModel):\n",
    "    searches: list[WebSearchItem] = Field(\n",
    "        description=\"A list of web searches to perform to best answer the query.\"\n",
    "    )\n",
    "\n",
    "\n",
    "class Resume(BaseModel):\n",
    "    resume_extract: str = Field(\n",
    "        description=\"The Extracted text from the loaded resume PDF\"\n",
    "    )\n",
    "\n",
    "    resume_url: str = Field(\n",
    "        description=\"The location of the resume pdf file. It can be wither hosted locally, or remotely\"\n",
    "    )\n",
    "\n",
    "\n",
    "class ReportData(BaseModel):\n",
    "    short_summary: str = Field(\n",
    "        description=\"A short 2-3 sentence summary of the findings.\"\n",
    "    )\n",
    "\n",
    "    markdown_report: str = Field(description=\"The final report\")\n",
    "\n",
    "    follow_up_questions: list[str] = Field(\n",
    "        description=\"Suggested topics to research further\"\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60c844be",
   "metadata": {},
   "source": [
    "### Read the Resume"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "3648cf18",
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_resume(url: Resume) -> Resume:\n",
    "    reader = PdfReader(url)\n",
    "    resume = \"\"\n",
    "    for page in reader.pages:\n",
    "        text = page.extract_text()\n",
    "        if text:\n",
    "            resume += text\n",
    "    return resume"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aaaaf80e",
   "metadata": {},
   "source": [
    "### The OpenAI Search Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "1c037862",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = \"You are a research assistant. Given a search term, you search the web for that term and \\\n",
    "produce a concise summary of the results. The summary must 2-3 paragraphs and less than 300 \\\n",
    "words. Capture the main points. Write succintly, no need to have complete sentences or good \\\n",
    "grammar. This will be consumed by someone synthesizing a report, so it's vital you capture the \\\n",
    "essence and ignore any fluff. Do not include any additional commentary other than the summary itself.\"\n",
    "\n",
    "search_agent = Agent(\n",
    "    name=\"Search agent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    tools=[WebSearchTool(search_context_size=\"low\")],\n",
    "    model=\"gpt-4o-mini\",\n",
    "    model_settings=ModelSettings(tool_choice=\"required\"),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bddfc470",
   "metadata": {},
   "source": [
    "### Planner Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "bae3e52d",
   "metadata": {},
   "outputs": [],
   "source": [
    "HOW_MANY_SEARCHES = 3\n",
    "\n",
    "INSTRUCTIONS = f\"You are a helpful research assistant specializing in UK immigration. \\\n",
    "Given a query about the UK Global Talent Visa, come up with a set of web searches to find the most current and accurate information. \\\n",
    "Focus on official sources, recent policy updates, requirements, and application guidance. \\\n",
    "Output {HOW_MANY_SEARCHES} search terms that will help gather up-to-date information about the UK Global Talent Visa.\"\n",
    "\n",
    "planner_agent = Agent(\n",
    "    name=\"PlannerAgent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    model=\"gpt-4o-mini\",\n",
    "    output_type=WebSearchPlan,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcc0739c",
   "metadata": {},
   "source": [
    "### Send Email Tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "513118f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def send_email(subject: str, html_body: str) -> Dict[str, str]:\n",
    "    \"\"\" Send out an email with the given subject and HTML body \"\"\"\n",
    "    sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))\n",
    "    from_email = Email(\"tochinwachukwu33@gmail.com\") # Change this to your verified email\n",
    "    to_email = To(\"tochinwachukwu33@gmail.com\") # Change this to your email\n",
    "    content = Content(\"text/html\", html_body)\n",
    "    mail = Mail(from_email, to_email, subject, content).get()\n",
    "    sg.client.mail.send.post(request_body=mail)\n",
    "    return \"success\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c08f0e95",
   "metadata": {},
   "source": [
    "### Send Email Agent using the Tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "68544fb0",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = \"\"\"You are able to send a nicely formatted HTML email based on a detailed report.\n",
    "You will be provided with a detailed report. You should use your tool to send one email, providing the \n",
    "report converted into clean, well presented HTML with an appropriate subject line.\"\"\"\n",
    "\n",
    "email_agent = Agent(\n",
    "    name=\"Email agent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    tools=[send_email],\n",
    "    model=\"gpt-4o-mini\",\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c6ba4cd",
   "metadata": {},
   "source": [
    "### Report Writing Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "c25532cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = (\n",
    "    \"You are a senior researcher tasked with writing a cohesive report for a research query. \"\n",
    "    \"You will be provided with the original query, and some initial research done by a research assistant.\\n\"\n",
    "    \"You should first come up with an outline for the report that describes the structure and \"\n",
    "    \"flow of the report. Then, generate the report and return that as your final output.\\n\"\n",
    "    \"The final output should be in markdown format, and it should be lengthy and detailed. Aim \"\n",
    "    \"for 5-10 pages of content, at least 1000 words.\"\n",
    ")\n",
    "\n",
    "writer_agent = Agent(\n",
    "    name=\"WriterAgent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    model=\"gpt-4o-mini\",\n",
    "    output_type=ReportData,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "7d1e0d21",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def plan_searches(query: str):\n",
    "    \"\"\"Use the planner_agent to plan which searches to run for the query\"\"\"\n",
    "    print(\"Planning searches...\")\n",
    "    result = await Runner.run(planner_agent, f\"Query: {query}\")\n",
    "    print(f\"Will perform {len(result.final_output.searches)} searches\")\n",
    "    return result.final_output\n",
    "\n",
    "\n",
    "async def perform_searches(search_plan: WebSearchPlan):\n",
    "    \"\"\"Call search() for each item in the search plan\"\"\"\n",
    "    print(\"Searching...\")\n",
    "    tasks = [asyncio.create_task(search(item)) for item in search_plan.searches]\n",
    "    results = await asyncio.gather(*tasks)\n",
    "    print(\"Finished searching\")\n",
    "    return results\n",
    "\n",
    "\n",
    "async def search(item: WebSearchItem):\n",
    "    \"\"\"Use the search agent to run a web search for each item in the search plan\"\"\"\n",
    "    input = f\"Search term: {item.query}\\nReason for searching: {item.reason}\"\n",
    "    result = await Runner.run(search_agent, input)\n",
    "    return result.final_output\n",
    "\n",
    "\n",
    "async def evaluate_profile(search_res, resume_text):\n",
    "    name = \"Tochi Nwachukwu\"\n",
    "    system_prompt = f\"You are an expert immigration consultant evaluating a resume against Global Talent Visa requirements. \\\n",
    "    Your task is to analyze {name}'s resume and assess how well it aligns with the visa criteria. \\\n",
    "    Provide a detailed, objective evaluation highlighting strengths, potential gaps, and recommendations for improvement. \\\n",
    "    Be thorough, professional, and constructive in your assessment.\"\n",
    "\n",
    "    system_prompt += f\"\\n\\n## Global Talent Visa Requirements:\\n{search_res}\\n\\n\"\n",
    "    system_prompt += f\"## Resume to Evaluate:\\n{resume_text}\\n\\n\"\n",
    "\n",
    "    user_message = f\"Please analyze {name}'s resume against the UK Global Talent Visa requirements provided. \\\n",
    "    In your evaluation:\\n\\\n",
    "    1. Identify which requirements are clearly met with supporting evidence from the resume\\n\\\n",
    "    2. Note any requirements that are partially met or unclear\\n\\\n",
    "    3. Highlight any gaps or missing elements\\n\\\n",
    "    4. Provide specific, actionable recommendations to strengthen the visa application\\n\\\n",
    "    5. Give an overall assessment of the likelihood of success\"\n",
    "\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": system_prompt},\n",
    "        {\"role\": \"user\", \"content\": user_message},\n",
    "    ]\n",
    "\n",
    "    response = openai.chat.completions.create(model=\"gpt-4o-mini\", messages=messages)\n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6acff25c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "### Evaluation of Tochi Nwachukwu's Resume Against UK Global Talent Visa Requirements\n",
      "\n",
      "#### 1. Requirements Clearly Met:\n",
      "\n",
      "- **Significant Expertise and Proven Track Record**: \n",
      "  Tochi describes over six years of hands-on experience as a DevOps Engineer, demonstrating significant expertise in architecting cloud workloads, particularly on AWS. His experience includes leading initiatives for the Federal Government of Nigeria and impactful projects in various sectors.\n",
      "  \n",
      "- **Professional Recognition**: \n",
      "  He has received a scholarship for academic excellence and was recognized as the Best Graduating Student in Heat and Mass Transfer, indicating his academic credentials and achievements.\n",
      "\n",
      "- **Professional Certifications**: \n",
      "  The AWS Certified Developer Associate and AWS Certified Cloud Practitioner indicate a high level of qualification. His ongoing certification efforts (with AWS SysOps Administrator in view) and pursuit of Google Professional Cybersecurity Certification further demonstrate commitment to professional development.\n",
      "\n",
      "- **Global Experience**: \n",
      "  Tochi has gained international experience, having worked as an AWS Cloud DevOps Engineer in Italy, and as a consultant in the USA. His role in Distributed in London indicates he has successfully navigated diverse work environments.\n",
      "\n",
      "#### 2. Requirements Partially Met or Unclear:\n",
      "\n",
      "- **Innovation and Contribution to the Field**: \n",
      "  While Tochi lists numerous projects and achievements, the resume could better articulate any innovations he has introduced or technical advancements that showcases significant contributions to the industry.\n",
      "\n",
      "- **Strong Portfolio of Work**: \n",
      "  Although he elaborates on his professional experience, a more detailed portfolio, including examples or metrics of significant projects that have had industry impacts, would strengthen his application.\n",
      "\n",
      "#### 3. Gaps or Missing Elements:\n",
      "\n",
      "- **Missing References or Endorsements**: \n",
      "  The Global Talent Visa often benefits from endorsements from recognized bodies or experts in the field. There are no mentions of endorsements or references in the resume that would support his expertise in the tech community.\n",
      "\n",
      "- **Specific Contributions to Technology**: \n",
      "  The resume lacks detailed descriptions of any innovative tools, processes, or frameworks he may have developed or contributed to that could exhibit leadership in the tech industry.\n",
      "\n",
      "- **Lack of Community Engagement**: \n",
      "  Engagement with professional communities or contributions to open-source projects can enhance his case for recognition in the tech landscape.\n",
      "\n",
      "#### 4. Specific, Actionable Recommendations:\n",
      "\n",
      "- **Gather Endorsements**: \n",
      "  Seek endorsements from previous employers, clients, or recognized professionals in the tech industry who can attest to Tochi’s exceptional abilities and influence in his field.\n",
      "\n",
      "- **Highlight Innovations**: \n",
      "  Clearly outline any innovations or processes he has developed that improved efficiency or contributed the technology landscape. For example, details regarding the architecture of a preceding project, or specific techniques he’s introduced in a previous role.\n",
      "\n",
      "- **Establish a Comprehensive Portfolio**: \n",
      "  Create a professional portfolio that details projects, contributions, and outcomes with quantifiable metrics illustrating the impact of his work.\n",
      "\n",
      "- **Community Engagement**: \n",
      "  Actively engage with tech communities, perhaps through speaking engagements at conferences, writing technical blogs, or contributing to open-source projects to strengthen the perception of his leadership in the field.\n",
      "\n",
      "- **Consolidate Technical Achievements**: \n",
      "  Summarize technical achievements and responsibilities held in prominent projects in an easily digestible format (success stories, case studies, etc.).\n",
      "\n",
      "#### 5. Overall Assessment of Likelihood of Success:\n",
      "\n",
      "Based on the current resume, Tochi’s likelihood of receiving a Global Talent Visa is moderate to high, provided he can bolster the application with additional information regarding innovations, endorsements, and community engagement, as well as articulated evidence of significant contributions to his field. By following the actionable recommendations above, he can significantly enhance his application and profile as a leading candidate for the Global Talent Visa.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/var/folders/c0/3t5lpmc91xqb9f5z7rjs1z7m0000gn/T/ipykernel_13602/3242160625.py:4: RuntimeWarning: coroutine 'evaluate_profile' was never awaited\n",
      "  profile_evaluation = await evaluate_profile(resume_text)\n",
      "RuntimeWarning: Enable tracemalloc to get the object allocation traceback\n"
     ]
    }
   ],
   "source": [
    "# resume_link = \"me/linkedin.pdf\"\n",
    "# resume_text = read_resume(resume_link)\n",
    "\n",
    "# profile_evaluation = await evaluate_profile(resume_text)\n",
    "# print(profile_evaluation)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "32df3773",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def write_report(query: str, search_results: list[str]):\n",
    "    \"\"\" Use the writer agent to write a report based on the search results\"\"\"\n",
    "    print(\"Thinking about report...\")\n",
    "    input = f\"Original query: {query}\\nSummarized search results: {search_results}\"\n",
    "    result = await Runner.run(writer_agent, input)\n",
    "    print(\"Finished writing report\")\n",
    "    return result.final_output\n",
    "\n",
    "async def send_email(report: ReportData):\n",
    "    \"\"\" Use the email agent to send an email with the report \"\"\"\n",
    "    print(\"Writing email...\")\n",
    "    result = await Runner.run(email_agent, report.markdown_report)\n",
    "    print(\"Email sent\")\n",
    "    return report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "e34b26d9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting research...\n",
      "Planning searches...\n",
      "Will perform 3 searches\n",
      "Searching...\n",
      "Finished searching\n",
      "Tochi Nwachukwu's resume demonstrates a strong background aligned with aspects of the UK Global Talent Visa requirements, primarily in the Digital Technology pathway. Below is a comprehensive evaluation based on the specified criteria.\n",
      "\n",
      "### 1. Requirements Clearly Met:\n",
      "\n",
      "- **Exceptional Talent in Digital Technology**: \n",
      "  - Tochi has over 6 years of experience as a DevOps Engineer, which includes architecting and building scalable cloud workloads primarily on AWS. His experience with organizations like Illuminem, Schull Technologies, and TalentUp demonstrates engagement in innovative technology solutions.\n",
      "  - He has led DevOps initiatives that align with the required criteria, showcasing leadership qualities and significant contributions to the digital technology sector.\n",
      "  \n",
      "- **Professional Certifications**:\n",
      "  - Certifications such as AWS Certified Developer Associate and AWS Certified Cloud Practitioner lend credibility to his expertise in cloud technologies, which is a significant aspect of the digital technology pathway.\n",
      "  \n",
      "- **International Recognition and Notable Projects**:\n",
      "  - His work in international projects, including those for foreign clients and major organizations in various countries, indicates a level of recognition in his field. He has developed systems utilized by many users globally, which enhances his profile regarding impact and reach.\n",
      "\n",
      "### 2. Requirements Partially Met or Unclear:\n",
      "\n",
      "- **Endorsement Requirements**:\n",
      "  - The resume does not explicitly mention any existing endorsements from recognized bodies or illustrious accolades. While he has impressive experience, without specific reference to an endorsement, it could be challenging to navigate the endorsement process.\n",
      "  \n",
      "- **Evidence of Impact**:\n",
      "  - While he provides examples of projects and responsibilities, tangible outcomes or metrics that demonstrate the impact of his work (e.g., efficiency improvements quantified or how international users have benefited) are limited. Specific numerical results from his initiatives could strengthen his profile further.\n",
      "\n",
      "### 3. Gaps or Missing Elements:\n",
      "\n",
      "- **Letters of Recommendation**:\n",
      "  - The resume does not indicate if Tochi has established connections with recognized experts who can vouch for his expertise. Letters of recommendation from reputable professionals in the tech sector would be beneficial. \n",
      "- **Clear Personal Statement**:\n",
      "  - A personal statement detailing his vision, objectives, and how he sees himself contributing to the UK’s digital technology landscape is not present. This document is essential to articulate his professional narrative succinctly.\n",
      "\n",
      "- **Upcoming Awards or Recognitions**:\n",
      "  - The absence of mention regarding any prestigious awards such as those recognized in digital technology could be seen as a gap in fulfilling the criteria for exceptional talent.\n",
      "\n",
      "### 4. Recommendations to Strengthen the Visa Application:\n",
      "\n",
      "- **Secure Endorsements**:\n",
      "  - Begin pursuing endorsements from recognized UK-based organizations in the tech industry, like Tech Nation or similar bodies aligning with his expertise. Engage with professionals in the field who can assist in this process.\n",
      "  \n",
      "- **Obtain Letters of Recommendation**:\n",
      "  - Actively seek letters of recommendation from senior professionals or established connections in the digital technology domain who can attest to his contributions and leadership capabilities.\n",
      "\n",
      "- **Add Quantifiable Achievements**:\n",
      "  - Rework the resume to include specific achievements and quantifiable results of his projects. For instance, percentages demonstrating systems improved under his leads, user growth, or operational efficiency gains would bolster the application significantly.\n",
      "\n",
      "- **Prepare a Personal Statement**:\n",
      "  - Draft a compelling personal statement that underlines his career trajectory, significant contributions to the field of digital technology, and aspirations for making an impact in the UK.\n",
      "\n",
      "- **Consider Additional Professional Associations**:\n",
      "  - Joining and being active in professional organizations within the tech landscape could enhance his credibility within the endorsement process.\n",
      "\n",
      "### 5. Overall Assessment of the Likelihood of Success:\n",
      "\n",
      "Tochi Nwachukwu presents a strong foundation for the Global Talent Visa with relevant experience, certifications, and notable projects signaling his potential as a leading talent in digital technology. However, addressing the identified gaps, particularly the endorsement process, obtaining recommendations, and providing quantifiable success metrics, is essential for improving his likelihood of success in the application process. If Tochi takes the actionable steps recommended, the chances of a successful application would increase significantly, especially if he can effectively convey his impact and leadership in the digital technology sector.\n",
      "Thinking about report...\n",
      "Finished writing report\n",
      "Writing email...\n",
      "Email sent\n",
      "Hooray!\n"
     ]
    }
   ],
   "source": [
    "resume_link = \"me/linkedin.pdf\"\n",
    "query = \"What are the detailed eligibility requirements for the UK Global Talent Visa? \\\n",
    "I want to evaluate whether a candidate's background meets the criteria for endorsement.\"\n",
    "\n",
    "with trace(\"Research trace\"):\n",
    "    print(\"Starting research...\")\n",
    "    resume_text = read_resume(resume_link)\n",
    "    search_plan = await plan_searches(query)\n",
    "    search_results = await perform_searches(search_plan)\n",
    "    profile_evaluation = await evaluate_profile(search_results, resume_text)\n",
    "    print(profile_evaluation)\n",
    "    report = await write_report(query, profile_evaluation)\n",
    "    await send_email(report)\n",
    "    print(\"Hooray!\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
